/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

import { pickedLineData } from '@amcax/base';
import {
  NumberInputFormat,
  PickInputRJSFFormat,
} from '@app-cad/common/components/command-form/constants';
import { PickableCommandForm } from '@app-cad/common/components/command-form/pickable';
import { useCommand } from '@app-cad/common/hooks/useCommand';
import { useTools } from '@app-cad/common/hooks/useTools';
import { CurvedBaseCommand, CurvedCmdDialogParams } from '@app-cad/types';
import { RJSFSchema } from '@rjsf/utils';
import { getIdOfPickedObj } from '@app-cad/common/utils/render';
import { useAsyncEffect } from 'ahooks';
import i18n from 'i18next';
import { get, omitBy } from 'lodash';
import { useState, useMemo } from 'react';

type Type = 'Spline' | 'Formula';

type Params = {
  type?: string;
  line?: string;
  spline?: string;
  scaleParam?: number;
  formula?: string;
};

type FormData = {
  type: Type;
  line?: pickedLineData;
  spline?: pickedLineData;
  scaleParam?: number;
  formula?: string;
};

function CommandExtendSurface({
  title,
  onClose,
  props,
}: CurvedCmdDialogParams) {
  const initData: FormData = {
    type: 'Spline',
    line: null,
    spline: null,
    scaleParam: 1,
  };

  const [formData, setFormData] = useState<FormData>(initData);

  const { picker } = useTools();

  const execute = (preview: boolean) => {
    const { type, line, spline, scaleParam, formula } = formData;

    const params: Params =
      type === 'Spline'
        ? {
            type: type,
            line: getIdOfPickedObj(line),
            spline: getIdOfPickedObj(spline),
            scaleParam,
          }
        : ({
            type: type,
            formula,
          } as Params);

    return confirmCommand({ a: params }, preview);
  };

  useAsyncEffect(async () => {
    if (props == null) {
      setFormData(initData);
      return;
    }

    const params: Params = props.params;
    const { type, line, spline, scaleParam = 1, formula } = params;

    await initEditDependency([line, spline]);

    setFormData({
      type: type as unknown as Type,
      line: picker.generatePickObjByPickID(line) as pickedLineData,
      spline: picker.generatePickObjByPickID(spline) as pickedLineData,
      scaleParam,
      formula: formula,
    });
  }, []);

  const checkAndFinishDraw = async () => {
    if (!isFormDataValid()) {
      return;
    }

    execute(false);

    onClose();
  };

  const dxid = get(props, 'dxid');

  const { initEditDependency, initingEdit, confirmCommand } = useCommand(
    'cmd-extend-curve',
    {
      commandName: 'CreateLawCurve',
      editDxid: dxid,
      onClose,
      finishDraw: checkAndFinishDraw,
    },
  );

  const isFormDataValid = () => {
    const { type, spline, line, formula } = formData;

    if (type === 'Spline') {
      return spline != null && line != null;
    }

    return formula != null;
  };

  const schema: RJSFSchema = useMemo(() => {
    const properties = omitBy(
      {
        spline:
          formData.type === 'Spline'
            ? {
                type: 'string',
                format: PickInputRJSFFormat.PickCurve,
              }
            : null,
        line:
          formData.type === 'Spline'
            ? {
                type: 'string',
                format: PickInputRJSFFormat.PickLine,
              }
            : null,
        scaleParam:
          formData.type === 'Spline'
            ? {
                title: '缩放',
                type: 'number',
                minimum: 1e-9,
                default: 1,
                format: NumberInputFormat.Real,
              }
            : null,
        formula:
          formData.type === 'Formula'
            ? {
                type: 'string',
                title: 'y =',
              }
            : null,
      },
      (val) => val == null,
    );

    return {
      type: 'object',
      properties: {
        type: {
          title: '模式',
          type: 'string',
          oneOf: [
            {
              type: 'string',
              title: '输入参考元素',
              const: 'Spline',
            },
            {
              type: 'string',
              title: '输入方程表达式',
              const: 'Formula',
            },
          ],
          default: 'Spline',
        },
        ...properties,
      },
    } as RJSFSchema;
  }, [formData.type]);

  return (
    <PickableCommandForm
      disabled={initingEdit}
      onClose={onClose}
      title={title}
      schema={schema}
      formData={formData}
      onChange={(v) => {
        setFormData(v);
      }}
      extraUiSchema={{
        spline: {
          'ui:placeholder': '请输入定义元素',
          'ui:autofocus': true,
        },
        line: {
          'ui:placeholder': '请输入参考元素',
        },
        formula: {
          'ui:placeholder': '请输入方程表达式',
        },
      }}
      submitText='完成'
      onSubmit={checkAndFinishDraw}
      isFormDataValid={isFormDataValid()}
    />
  );
}

export const cmdLawCurve: CurvedBaseCommand = {
  id: 'CmdLawCurve',
  label: 'command.law-curve',
  icon: 'commands/curved/law-curve',
  create: (label, onClose, props) => (
    <CommandExtendSurface
      title={i18n.t(label)}
      onClose={onClose}
      props={props}
    />
  ),
};
